/*
 *  Copyright 2004 Blandware (http://www.blandware.com)
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 */
package com.blandware.atleap.webapp.taglib.core.menu.context;

import com.blandware.atleap.webapp.taglib.core.ParamParent;
import com.blandware.atleap.webapp.taglib.core.html.LinkTag;
import com.blandware.atleap.webapp.util.core.WebappConstants;
import org.apache.commons.validator.GenericValidator;

import javax.servlet.jsp.JspException;
import javax.servlet.jsp.JspTagException;
import java.io.IOException;

/**
 * <p>Placed inside tag which renders part of context menu item, this tag
 * renders HTML element, which will act as hyperlink.
 * <br />
 * This tag is only valid when nested within <em>itemEnabled</em> or
 * <em>itemDisabled</em> tag (which must be nested within <em>item</em> tag).
 * </p>
 * <p>When content is rendered to page, this tag suppresses rendering of A tag,
 * IF AND ONLY IF it's a child of <em>itemDisabled</em> tag, else it just calls
 * super methods (so, usual A tag is rendered). Otherwise, it renders DIV
 * element that is a part of context menu structure.</p>
 * <p>
 * Allowed attributes are:
 * <ul>
 * <li>
 * <b>confirmExpression</b> - javascript expression used to determine, whether
 * or not to follow link on click. This expression should produce boolean value.
 * Will be added to 'onclick' event handler. You should not specify 'onclick'
 * event handler manually for this tag, because its value will be replaced with
 * our JavaScript code.<br />
 * Note: this should be expression, not operator (like 'return').
 * </li>
 * <li>
 * <b>highlightedStyleClass</b> - class of highlighted context menu item that
 * will be generated by this tag
 * </li>
 * <li>
 * <b>disabledStyleClass</b> - class of disabled context menu item that will be
 * generated by this tag
 * </li>
 * <li>
 * <b>highlightedDisabledStyleClass</b> - class of highlighted disabled context
 * menu item that will be generated by this tag
 * </li>
 * </ul>
 * Some attributes are inherited from
 * {@link com.blandware.atleap.webapp.taglib.core.BaseHandlerTag}.
 * </p>
 * <p><a href="ItemLinkTag.java.html"><i>View Source</i></a></p>
 *
 * @author Sergey Zubtsovskiy <a href="mailto:sergey.zubtsovskiy@blandware.com">&lt;sergey.zubtsovskiy@blandware.com&gt;</a>
 * @version $Revision: 1.13 $ $Date: 2006/08/03 10:08:25 $
 * @see ItemTag
 * @see ItemLabelTag
 * @jsp.tag name="itemLink"
 * body-content="scriptless"
 */
public class ItemLinkTag extends LinkTag implements ParamParent {

	/**
	 * Javascript expression used to determine, whether or not to follow link on click. This expression should produce boolean value.
	 * Will be added to 'onclick' event handler. You should not specify 'onclick' event handler manually for this tag,
	 * because its value will be replaced with our JavaScript code
	 */
	protected String confirmExpression;

    /**
     * This is class of highlighted context menu item that will be generated
     * by this tag
     */
    protected String highlightedStyleClass = null;

    /**
     * This is class of disabled context menu item that will be generated
     * by this tag
     */
    protected String disabledStyleClass = null;

    /**
     * This is class of highlighted disabled context menu item that will be generated
     * by this tag
     */
    protected String highlightedDisabledStyleClass = null;

	/**
	 * Internal flag, used in overridden methods from LinkTag to determine action to perform
	 */
	protected int renderingFlag = ItemPart.FLAG_RENDER_TO_PAGE;

    /**
     * Internal flag, used to store info whether item tag to which this tag
     * belongs is enabled. For disabled one no links will be generated.
     */
    protected boolean isItemEnabled;

	/**
     * Returns confirm JS expression
     *
     * @return confirm expression
     * @see #confirmExpression
	 * @jsp.attribute required="false"
	 * rtexprvalue="true"
	 * type="java.lang.String"
	 * description="Javascript expression used to determine, whether or not follow link on click"
	 */
	public String getConfirmExpression() {
		return confirmExpression;
	}

    /**
     * Sets confirm JS expression
     *
     * @param confirmExpression confirm expression to set
     * @see #confirmExpression
     */
	public void setConfirmExpression(String confirmExpression) {
		this.confirmExpression = confirmExpression;
	}

    /**
     * Returns class of highlighted context menu item
     *
     * @return class of highlighted context menu item
     * @see #highlightedStyleClass
     * @jsp.attribute required="false"
	 * rtexprvalue="true"
	 * type="java.lang.String"
	 * description="Class of highlighted context menu item"
     */
    public String getHighlightedStyleClass() {
        return highlightedStyleClass;
    }

    /**
     * Sets class of highlighted context menu item
     *
     * @param highlightedStyleClass class of highlighted context menu item to set
     * @see #highlightedStyleClass
     */
    public void setHighlightedStyleClass(String highlightedStyleClass) {
        this.highlightedStyleClass = highlightedStyleClass;
    }

    /**
     * Returns class of disabled context menu item
     *
     * @return class of disabled context menu item
     * @see #disabledStyleClass
     * @jsp.attribute required="false"
	 * rtexprvalue="true"
	 * type="java.lang.String"
	 * description="Class of disabled context menu item"
     */
    public String getDisabledStyleClass() {
        return disabledStyleClass;
    }

    /**
     * Sets class of disabled context menu item
     *
     * @param disabledStyleClass class to set
     */
    public void setDisabledStyleClass(String disabledStyleClass) {
        this.disabledStyleClass = disabledStyleClass;
    }

    /**
     * Returns class of highlighted disabled context menu item
     *
     * @return class of highlighted disabled context menu item
     * @see #highlightedDisabledStyleClass
     * @jsp.attribute required="false"
	 * rtexprvalue="true"
	 * type="java.lang.String"
	 * description="Class of highlighted disabled context menu item"
     */
    public String getHighlightedDisabledStyleClass() {
        return highlightedDisabledStyleClass;
    }

    /**
     * Sets class of highlighted disabled context menu item
     *
     * @param highlightedDisabledStyleClass class to set
     */
    public void setHighlightedDisabledStyleClass(String highlightedDisabledStyleClass) {
        this.highlightedDisabledStyleClass = highlightedDisabledStyleClass;
    }

	/**
	 * Performs tag logic
	 *
	 * @throws JspException
	 */
	public void doTag() throws JspException, IOException {

		// search for parent ItemPart
		ItemPart part = (ItemPart) findAncestorWithClass(this, ItemPart.class);
		if ( part == null ) {
			throw new JspTagException("This tag is only valid when nested within 'itemEnabled' or 'itemDisabled' tag");
		}

        ItemTag parentItemTag = (ItemTag) findAncestorWithClass(this, ItemTag.class);
        if (parentItemTag == null) {
            throw new JspTagException("This tag is only valid when nested within 'item' tag");
        }
        // to prevent appearance of pressable link
        isItemEnabled = parentItemTag.getEnabled().booleanValue();

		// save flag from parent ItemPart, disable parameters validation and call super method
		renderingFlag = part.getRenderingFlag();
        suppressValidation = true;
		super.doTag();
	}

	/**
	 * If we're rendering to page, appends opening tag of HTML element, which
     * renders a hyperlink, to the specified StringBuffer. Otherwise, creates
     * a div.
     *
     * @param element where to write
	 */
	protected void openElement(StringBuffer element) {
		if ( renderingFlag == ItemPart.FLAG_RENDER_TO_MENU ) {
			element.append("<div ");
		} else {
            if (isItemEnabled) {
			    super.openElement(element);
            }
		}
	}

	/**
	 * @see com.blandware.atleap.webapp.taglib.core.html.LinkTag#appendLocation(StringBuffer, String)
	 */
	protected void appendLocation(StringBuffer element, String location) {
		if ( renderingFlag == ItemPart.FLAG_RENDER_TO_MENU ) {
            if (GenericValidator.isBlankOrNull(location)) {
                location = "";
            }
			element.append("url=\"").append(location).append("\"");
		} else {
            if (isItemEnabled) {
                if (name == null && action == null && forward == null && href == null) {
                    href = "#";
                }
			    super.appendLocation(element, location);
            }
		}
	}

	/**
	 * @see com.blandware.atleap.webapp.taglib.core.html.LinkTag#appendAttributes(StringBuffer)
	 */
	protected void appendAttributes(StringBuffer element) {
		if ( !GenericValidator.isBlankOrNull(confirmExpression) ) {
			confirmExpression = "eval('" + confirmExpression.replaceAll("\\'", "\\\\'") + "')";
		}
		if ( renderingFlag == ItemPart.FLAG_RENDER_TO_MENU ) {
			// override JS attributes
			onclick = "onMenuItemClick(this);";
			if ( !GenericValidator.isBlankOrNull(confirmExpression) ) {
                onclick = "if ( " + confirmExpression + " ) { " + onclick + "} else { return false;}";
			}
            if (GenericValidator.isBlankOrNull(styleClass)) {
                styleClass = WebappConstants.CONTEXT_MENU_ITEM_STYLE_CLASS;
            }
            if (GenericValidator.isBlankOrNull(highlightedStyleClass)) {
                highlightedStyleClass = WebappConstants.HIGHLIGHTED_CONTEXT_MENU_ITEM_STYLE_CLASS;
            }
            if (GenericValidator.isBlankOrNull(disabledStyleClass)) {
                disabledStyleClass = WebappConstants.DISABLED_CONTEXT_MENU_ITEM_STYLE_CLASS;
            }
            if (GenericValidator.isBlankOrNull(highlightedDisabledStyleClass)) {
                highlightedDisabledStyleClass = WebappConstants.HIGHLIGHTED_DISABLED_CONTEXT_MENU_ITEM_STYLE_CLASS;
            }
            if (!isItemEnabled) {
                styleClass = disabledStyleClass;
                highlightedStyleClass = highlightedDisabledStyleClass;
            }
            onmouseover = "activateContextMenuItem(this, '" + highlightedStyleClass + "');";
            onmouseout = "deactivateContextMenuItem(this, '" + styleClass + "');";
		} else {
			onclick = "return " + confirmExpression + ";";
		}
        if (renderingFlag == ItemPart.FLAG_RENDER_TO_MENU || isItemEnabled) {
		    super.appendAttributes(element);
        }
	}

    /**
	 * @see com.blandware.atleap.webapp.taglib.core.html.LinkTag#closeOpeningTag(StringBuffer)
	 */
    protected void closeOpeningTag(StringBuffer element) {
		if ( renderingFlag == ItemPart.FLAG_RENDER_TO_MENU ) {
			element.append(">");
		} else {
            if (isItemEnabled) {
			    super.closeOpeningTag(element);
            }
		}
    }

	/**
	 * @see com.blandware.atleap.webapp.taglib.core.html.LinkTag#closeElement(StringBuffer)
	 */
	protected void closeElement(StringBuffer element) {
		if ( renderingFlag == ItemPart.FLAG_RENDER_TO_MENU ) {
			element.append("</div>");
		} else {
            if (isItemEnabled) {
			    super.closeElement(element);
            }
		}
	}

}
